#pragma once
#include <iostream>
#include <unistd.h>
#include <fstream>
#include <filesystem>
#include <memory>
#include <time.h>
#include <sstream>
namespace MyLog
{
    const std::string logpath = "./log/";  // 日志文件的保存位置
    const std::string logname = "log.txt"; // 日志文件名

    // 日志等级
    enum class Loglevel
    {
        DUBUG = 1,
        RUNNING,
        WARNING,
        ERROR,
        FATAL
    };
    std::string GetCurtime()
    {
        time_t temp = time(nullptr);
        struct tm t;
        localtime_r(&temp, &t);
        char buffer[1024];
        snprintf(buffer, sizeof(buffer), "%4d-%02d-%02d %02d:%02d:%02d",
                 t.tm_year + 1900,
                 t.tm_mon + 1,
                 t.tm_wday + 1,
                 t.tm_hour,
                 t.tm_min,
                 t.tm_sec);
        return buffer;
    }
    std::string LogTostring(Loglevel loglevel)
    {
        switch (loglevel)
        {
        case Loglevel::DUBUG:
            return "DUBUG";
        case Loglevel::RUNNING:
            return "RUNNING";
        case Loglevel::WARNING:
            return "WARNING";
        case Loglevel::ERROR:
            return "ERROR";
        case Loglevel::FATAL:
            return "FATAL";
        default:
            return "NONE";
        }
    }
    // 策略模式
    class Strategy
    {
    public:
        virtual ~Strategy() = default;
        virtual void SyncLog(const std::string &message) = 0; // 设置为抽象类，由子类来实现
    };
    // 向屏幕输出
    class ConsoleStrategy : public Strategy
    {
    public:
        ConsoleStrategy()
        {
        }
        void SyncLog(const std::string &message)
        {
            std::cout << message << std::endl;
        }
        ~ConsoleStrategy()
        {
        }
    };
    class FilesystemStrategy : public Strategy
    {
    public:
        FilesystemStrategy()
            :_filename(logpath + logname)
        {
            if (std::filesystem::exists(logpath.c_str())) // 如果目录存在就返回，不存在就创建
            {
                return;
            }
            else
            {
                try
                {
                    std::filesystem::create_directories(logpath.c_str());
                }
                catch (std::filesystem::filesystem_error &e)
                {
                    std::cout << e.what() << std::endl;
                }
            }
        }
        void SyncLog(const std::string &message)
        {
            std::ofstream out(_filename.c_str(), std::ios::app);
            if (!out.is_open())
                return;     // 如果没有正常打开就返回
            out << message << std::endl; // 把内容写道文件流当中
        }
        ~FilesystemStrategy()
        {
        }
    private:
        std::string _filename;
    };

    // 日志类实现
    class Logger
    {
    public:
        Logger()
        {
            _strategy = std::make_shared<ConsoleStrategy>();
        }
        void EnableConsoleStrategy()
        {
            _strategy = std::make_shared<ConsoleStrategy>();
        }
        void EnableFilesystemStrategy()
        {
            _strategy = std::make_shared<FilesystemStrategy>();
        }

        // 内部类，一个Message对象代表一条完整的日志信息
        class Message
        {
        public:
            Message(std::string filename, int line, Loglevel loglevel, Logger& logger)
                : _filename(filename),
                  _line(line),
                  _loglevel(loglevel),
                  _logger(logger)
            {
                std::stringstream ss;
                ss  << "[" << GetCurtime() << "] "
                    << "[" << LogTostring(_loglevel) << "] "
                    << "[" << getpid() << "] "
                    << "[" << _filename << "] "
                    << "[" << _line << "] "
                    << " - ";
                _loginfo += ss.str();
            }

            template<class T>
            Message& operator<<(const T& info)
            {
                std::stringstream ss;
                ss << info;
                _loginfo += ss.str();
                return *this;
            }
            ~Message()
            {
                if (_logger._strategy)
                {
                    _logger._strategy->SyncLog(_loginfo);
                }
            }

        private:
            Loglevel _loglevel;
            int _line;
            std::string _filename;
            std::string _loginfo; // 代表着完整的信息
            Logger& _logger;
        };

        Message operator()(std::string filename, int line, Loglevel loglevel)
        {
            return Message(filename,line,loglevel,*this);
        }

        ~Logger()
        {

        }

    private:
        std::shared_ptr<Strategy> _strategy;
    };

    Logger logger;

    #define LOG(type) logger(__FILE__,__LINE__,type)
    #define ENABLE_CONSOSLE_STRATEGY() logger.EnableConsoleStrategy()
    #define ENABLE_FILESYSTEM_STRATEGY() logger.EnableFilesystemStrategy()
}